package com.pai4j.common.config.annotation;

import com.pai4j.common.enums.ArticleStatusEnum;
import com.pai4j.common.enums.CreatorStatusEnum;
import com.pai4j.common.exception.AuthException;
import com.pai4j.common.helper.SessionHelper;
import com.pai4j.domain.vo.response.creator.CreatorDetailResponseVO;
import com.pai4j.remote.pgc.CreatorClient;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 创作者身份校验拦截器
 * 拦截标记了@RequireCreator注解的方法，校验用户的创作者身份
 *
 * @author: CYM-pai
 * @date: 2025/11/01
 */
@Slf4j
public class RequireCreatorInterceptor implements HandlerInterceptor {
    
    @Resource
    private CreatorClient creatorClient;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        
        // 只对public方法生效
        if (Modifier.PUBLIC != method.getModifiers()) {
            return true;
        }
        
        // 获取@RequireCreator注解
        RequireCreator requireCreator = method.getAnnotation(RequireCreator.class);
        if (requireCreator == null) {
            // 方法没有注解，不需要拦截
            return true;
        }
        
        try {
            // 1. 获取用户ID
            String userId = getUserId(requireCreator, handlerMethod);
            if (StringUtils.isBlank(userId)) {
                throw new AuthException("用户未登录！");
            }
            
            // 2. 如果允许草稿不校验，判断是否为草稿状态
            if (requireCreator.allowDraft()) {
                Integer status = getStatus(requireCreator, handlerMethod);
                if (status != null && ArticleStatusEnum.DRAFT.getStatus().equals(status)) {
                    // 草稿状态，跳过创作者校验
                    log.debug("草稿状态，跳过创作者身份校验: userId={}", userId);
                    return true;
                }
            }
            
            // 3. 校验创作者身份
            validateCreatorStatus(userId, requireCreator.message());
            
            return true;
            
        } catch (AuthException e) {
            // 直接抛出认证异常
            throw e;
        } catch (Exception e) {
            log.error("创作者身份校验异常", e);
            throw new AuthException("创作者身份校验失败：" + e.getMessage());
        }
    }
    
    /**
     * 获取用户ID
     */
    private String getUserId(RequireCreator annotation, HandlerMethod handlerMethod) {
        // 如果指定了参数名，从方法参数中获取
        if (StringUtils.isNotBlank(annotation.userIdParam())) {
            return getParamValue(handlerMethod, annotation.userIdParam(), String.class);
        }
        
        // 默认从Session获取当前登录用户
        return SessionHelper.getCurrentUserId();
    }
    
    /**
     * 获取状态值
     */
    private Integer getStatus(RequireCreator annotation, HandlerMethod handlerMethod) {
        String statusParam = annotation.statusParam();
        if (StringUtils.isBlank(statusParam)) {
            return null;
        }
        
        return getParamValue(handlerMethod, statusParam, Integer.class);
    }
    
    /**
     * 从方法参数中获取指定字段的值
     */
    @SuppressWarnings("unchecked")
    private <T> T getParamValue(HandlerMethod handlerMethod, String fieldName, Class<T> targetType) {
        try {
            Object[] args = handlerMethod.getMethodParameters();
            if (args == null || args.length == 0) {
                return null;
            }
            
            // 遍历所有参数，查找包含指定字段的对象
            for (Object arg : args) {
                if (arg == null) {
                    continue;
                }
                
                // 直接获取字段值
                try {
                    Field field = arg.getClass().getDeclaredField(fieldName);
                    field.setAccessible(true);
                    Object value = field.get(arg);
                    
                    if (value != null && targetType.isAssignableFrom(value.getClass())) {
                        return (T) value;
                    }
                } catch (NoSuchFieldException e) {
                    // 当前对象没有该字段，继续查找下一个参数
                    continue;
                }
            }
            
        } catch (Exception e) {
            log.warn("获取参数值失败: fieldName={}", fieldName, e);
        }
        
        return null;
    }
    
    /**
     * 校验创作者身份
     */
    private void validateCreatorStatus(String userId, String customMessage) {
        try {
            // 调用远程服务获取创作者信息
            var response = creatorClient.getCreatorInfo(userId);
            
            if (response == null || !response.isSuccess()) {
                String message = StringUtils.isNotBlank(customMessage) ? 
                        customMessage : "请先申请成为创作者！";
                throw new AuthException(message);
            }
            
            CreatorDetailResponseVO creator = response.getData();
            
            // 检查是否为创作者
            if (creator == null || creator.getId() == null) {
                String message = StringUtils.isNotBlank(customMessage) ? 
                        customMessage : "请先申请成为创作者！";
                throw new AuthException(message);
            }
            
            // 检查创作者状态是否已通过审核
            if (!CreatorStatusEnum.APPROVED.getCode().equals(creator.getStatus())) {
                String statusDesc = creator.getStatusDesc();
                String message = StringUtils.isNotBlank(customMessage) ? 
                        customMessage : "创作者审核未通过，无法进行此操作！当前状态：" + statusDesc;
                throw new AuthException(message);
            }
            
            log.debug("创作者身份校验通过: userId={}, creatorName={}", userId, creator.getCreatorName());
            
        } catch (AuthException e) {
            throw e;
        } catch (Exception e) {
            log.error("创作者身份校验异常: userId={}", userId, e);
            String message = StringUtils.isNotBlank(customMessage) ? 
                    customMessage : "创作者身份校验失败";
            throw new AuthException(message);
        }
    }
}

